/**
 * com.chaeron.GPS - An API for access to GPS devices.
 *
 *
 * Copyright (c) 2001, 2002 Chaeron Corporation,
 * All rights reserved.
 * 
 * Chaeron grants you a non-exclusive license to use, modify and re-distribute
 * this program under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version, provided that this copyright notice and 
 * license appear on all copies of the software.
 * 
 * Software is provided "AS IS," without a warranty of any kind. ALL EXPRESS OR
 * IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
 * HEREBY EXCLUDED. THE ENTIRE RISK ARISING OUT OF USING THE SOFTWARE IS ASSUMED
 * BY THE LICENSEE. See the GNU General Public License for more details.
 *
 * CHAERON AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
 * LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR DISTRIBUTING SOFTWARE.
 * IN NO EVENT WILL CHAERON OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE,
 * PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL
 * OR PUNITIVE DAMAGES, HOWEVER CAUSED AN REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF CHAERON HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 * @version     1.02
 * @author  	Andrzej Jan Taramina, Chaeron Corporation
 *  			andrzej@chaeron.com
 */

package com.chaeron.GPS.Garmin;

//***************************************************************************
//*
//* 	Imports
//*
//***************************************************************************/

//***************************************************************************
//*
//* 	Protocol Class definition
//*
//***************************************************************************/

/**
 * The Protocol class contains Garmin Protocol Data tables
 *
 */

public class Protocol 
{
	//***************************************************************************
	//*
	//* 	Link Protocol definitions
	//*
	//***************************************************************************/
	
	final static short        LINK_PROTOCOL_L001				= 1;
	final static short        LINK_PROTOCOL_L002				= 2;
	
	
	//***************************************************************************
	//*
	//* 	Application Protocol definitions
	//*
	//***************************************************************************/
	
	// Application Protocol Types
	
	final static int			APP_PROTOCOL_COMMAND			= 0;
	final static int			APP_PROTOCOL_WAYPOINT_XFER		= 1;
	final static int			APP_PROTOCOL_ROUTE_XFER			= 2;
	final static int			APP_PROTOCOL_TRACKLOG_XFER		= 3;
	final static int			APP_PROTOCOL_PRX_XFER			= 4;
	final static int			APP_PROTOCOL_ALMANAC_XFER		= 5;
	final static int			APP_PROTOCOL_DATETIME_INIT		= 6;
	final static int			APP_PROTOCOL_POSITION_INIT		= 7;
	final static int			APP_PROTOCOL_PVT				= 8;
	
	// App Protocol Array indexes
	
	final static int			APP_PROTOCOL_LAST				= APP_PROTOCOL_PVT;
	
	final static int			APP_PROTOCOL_SELECTOR			= APP_PROTOCOL_LAST + 1;
	
	final static int			APP_PROTOCOL_ID					= 0;
	final static int			APP_PROTOCOL_SWVER				= 1;
	final static int			APP_PROTOCOL_LINK				= 2;
	
	
	//***************************************************************************
	//*
	//* 	Data Protocol definitions
	//*
	//***************************************************************************/
	
	// Data Protocol Types

	final static short        DATA_PROTOCOL_1					= 1;
	final static short        DATA_PROTOCOL_2					= 2;
	final static short        DATA_PROTOCOL_3					= 3;
	
	
	// Data Protocol Definitions
	
	final static short        DATA_PROTOCOL_UNDEFINED			= 0;
	final static short        DATA_PROTOCOL_D100				= 100;
	final static short        DATA_PROTOCOL_D101				= 101;
	final static short        DATA_PROTOCOL_D102				= 102;
	final static short        DATA_PROTOCOL_D103				= 103;
	final static short        DATA_PROTOCOL_D104				= 104;
	final static short        DATA_PROTOCOL_D105				= 105;
	final static short        DATA_PROTOCOL_D106				= 106;
	final static short        DATA_PROTOCOL_D107				= 107;
	final static short        DATA_PROTOCOL_D108				= 108;
	final static short        DATA_PROTOCOL_D109				= 109;
	final static short        DATA_PROTOCOL_D150				= 150;
	final static short        DATA_PROTOCOL_D151				= 151;
	final static short        DATA_PROTOCOL_D152				= 152;
	final static short        DATA_PROTOCOL_D154				= 154;
	final static short        DATA_PROTOCOL_D155				= 155;
	final static short        DATA_PROTOCOL_D200				= 200;
	final static short        DATA_PROTOCOL_D201				= 201;
	final static short        DATA_PROTOCOL_D202				= 202;
	final static short        DATA_PROTOCOL_D210				= 210;
	final static short        DATA_PROTOCOL_D300				= 300;
	final static short        DATA_PROTOCOL_D301				= 301;
	final static short        DATA_PROTOCOL_D310				= 310;
	
	
	//***************************************************************************
	//*
	//* 	Packet ID definitions
	//*
	//***************************************************************************/
	
	// Packet ID types
	
	final static byte         GARMIN_PID_UNKNOWN          	    = 0;
	final static byte         GARMIN_PID_ERROR	          	    = 3;
	final static byte         GARMIN_PID_ACK		            = 6;
	final static byte         GARMIN_PID_NACK		            = 21;
	final static byte         GARMIN_PID_PROTOCOL_ARRAY		    = (byte)253;
	final static byte         GARMIN_PID_PRODUCT_REQ		    = (byte)254;
	final static byte         GARMIN_PID_PRODUCT_DATA		    = (byte)255;
	
	
	// Link Protocol specific Packet ID indexes  
	
	final static byte         GARMIN_PID_COMMAND				= 0;
	final static byte         GARMIN_PID_XFER_COMPLETE			= 1;
	final static byte         GARMIN_PID_DATE_TIME				= 2;
	final static byte         GARMIN_PID_POSITION				= 3;
	final static byte         GARMIN_PID_PRX_WAYPOINT			= 4;
	final static byte         GARMIN_PID_RECORDS				= 5;
	final static byte         GARMIN_PID_ROUTE_HDR				= 6;
	final static byte         GARMIN_PID_ROUTE_WAYPOINT			= 7;
	final static byte         GARMIN_PID_ALMANAC				= 8;
	final static byte         GARMIN_PID_TRACK_POINT			= 9;
	final static byte         GARMIN_PID_WAYPOINT				= 10;
	final static byte         GARMIN_PID_PVT					= 11;
	final static byte         GARMIN_PID_ROUTE_LINK				= 12;
	final static byte         GARMIN_PID_TRACK_HDR				= 13;
	final static byte         GARMIN_PID_LAST					= GARMIN_PID_TRACK_HDR;
	
	
	// L001 Protocol Packet ID definitions.  
	
	final static byte         		GARMIN_PID_L001_COMMAND				= 10;
	final static byte         		GARMIN_PID_L001_XFER_COMPLETE		= 12;
	final static byte         		GARMIN_PID_L001_DATE_TIME			= 14;
	final static byte         		GARMIN_PID_L001_POSITION			= 17;
	final static byte        		GARMIN_PID_L001_PRX_WAYPOINT		= 19;
	final static byte         		GARMIN_PID_L001_RECORDS				= 27;
	final static byte        		GARMIN_PID_L001_ROUTE_HDR			= 29;
	final static byte        		GARMIN_PID_L001_ROUTE_WAYPOINT		= 30;
	final static byte         		GARMIN_PID_L001_ALMANAC				= 31;
	final static byte         		GARMIN_PID_L001_TRACK_POINT			= 34;
	final static byte         		GARMIN_PID_L001_WAYPOINT			= 35;
	final static byte         		GARMIN_PID_L001_PVT					= 51;
	final static byte         		GARMIN_PID_L001_ROUTE_LINK			= 98;
	final static byte         		GARMIN_PID_L001_TRACK_HDR			= 99;
	
	
	// L002 Protocol Packet ID definitions.  
	
	final static byte      	 	  	GARMIN_PID_L002_ALMANAC				= 4;
	final static byte       		GARMIN_PID_L002_COMMAND				= 11;
	final static byte         		GARMIN_PID_L002_XFER_COMPLETE		= 12;
	final static byte         		GARMIN_PID_L002_DATE_TIME			= 20;
	final static byte         		GARMIN_PID_L002_POSITION			= 24;
	final static byte         		GARMIN_PID_L002_RECORDS				= 35;
	final static byte         		GARMIN_PID_L002_ROUTE_HDR			= 37;
	final static byte         		GARMIN_PID_L002_ROUTE_WAYPOINT		= 39;
	final static byte         		GARMIN_PID_L002_WAYPOINT			= 43;
	
	
	// Packet ID Lookup Table (by link protocol)  
	
	final static private byte[][]			linkPacketIDs					 	= 
	{
		{ GARMIN_PID_L001_COMMAND, 			GARMIN_PID_L002_COMMAND },
		{ GARMIN_PID_L001_XFER_COMPLETE, 	GARMIN_PID_L002_XFER_COMPLETE },
		{ GARMIN_PID_L001_DATE_TIME, 		GARMIN_PID_L002_DATE_TIME },
		{ GARMIN_PID_L001_POSITION, 		GARMIN_PID_L002_POSITION },
		{ GARMIN_PID_L001_PRX_WAYPOINT, 	GARMIN_PID_L002_RECORDS },
		{ GARMIN_PID_L001_RECORDS , 		GARMIN_PID_L002_COMMAND },
		{ GARMIN_PID_L001_ROUTE_HDR, 		GARMIN_PID_L002_ROUTE_HDR },
		{ GARMIN_PID_L001_ROUTE_WAYPOINT, 	GARMIN_PID_L002_ROUTE_WAYPOINT },
		{ GARMIN_PID_L001_ALMANAC, 			GARMIN_PID_L002_ALMANAC },
		{ GARMIN_PID_L001_TRACK_POINT, 		GARMIN_PID_UNKNOWN },
		{ GARMIN_PID_L001_WAYPOINT, 		GARMIN_PID_L002_WAYPOINT },
		{ GARMIN_PID_L001_PVT, 				GARMIN_PID_UNKNOWN },
		{ GARMIN_PID_L001_ROUTE_LINK, 		GARMIN_PID_UNKNOWN },
		{ GARMIN_PID_L001_TRACK_HDR, 		GARMIN_PID_UNKNOWN }
	};
	
	
	// Packet ID String Lookup Table (by link protocol)  
	
	final static private String[][]		linkPacketIDStrings					 	= 
	{
		{ "COMMAND", 			"COMMAND" },
		{ "XFER_COMPLETE", 		"XFER_COMPLETE" },
		{ "DATE_TIME", 			"DATE_TIME" },
		{ "POSITION", 			"POSITION" },
		{ "PRX_WAYPOINT", 		"RECORDS" },
		{ "RECORDS", 			"COMMAND" },
		{ "ROUTE_HDR", 			"ROUTE_HDR" },
		{ "ROUTE_WAYPOINT", 	"ROUTE_WAYPOINT" },
		{ "ALMANAC", 			"ALMANAC" },
		{ "TRACK", 				"UNKNOWN" },
		{ "WAYPOINT", 			"WAYPOINT" },
		{ "PVT", 				"UNKNOWN" },
		{ "ROUTE_LINK", 		"UNKNOWN" },
		{ "TRACK_HDR", 			"UNKNOWN" }
	};
	
	
	//***************************************************************************
	//*
	//* 	Command definitions
	//*
	//***************************************************************************/
	
	
	// Command Types
	
	final static byte        	 	COMMAND_XFER_ABORT						= 0;
	final static byte       	  	COMMAND_XFER_ALMANAC					= 1;
	final static byte         		COMMAND_XFER_POSITION					= 2;
	final static byte         		COMMAND_XFER_PRX_WAYPOINTS				= 3;
	final static byte         		COMMAND_XFER_ROUTES						= 4;
	final static byte         		COMMAND_XFER_TIME						= 5;
	final static byte         		COMMAND_XFER_TRACKS						= 6;
	final static byte         		COMMAND_XFER_WAYPOINTS					= 7;
	final static byte         		COMMAND_POWER_OFF						= 8;
	final static byte         		COMMAND_PVT_START						= 9;
	final static byte         		COMMAND_PVT_END							= 10;
	final static byte         		COMMAND_UNAVAILABLE						= -1;
	
	
	// A010 Protocol Command definitions.  
	
	final static byte         		COMMAND_A010_XFER_ABORT					= 0;
	final static byte         		COMMAND_A010_XFER_ALMANAC				= 1;
	final static byte         		COMMAND_A010_XFER_POSITION				= 2;
	final static byte         		COMMAND_A010_XFER_PRX_WAYPOINTS			= 3;
	final static byte         		COMMAND_A010_XFER_ROUTES				= 4;
	final static byte         		COMMAND_A010_XFER_TIME					= 5;
	final static byte         		COMMAND_A010_XFER_TRACKS				= 6;
	final static byte         		COMMAND_A010_XFER_WAYPOINTS				= 7;
	final static byte         		COMMAND_A010_POWER_OFF					= 8;
	final static byte         		COMMAND_A010_PVT_START					= 49;
	final static byte         		COMMAND_A010_PVT_END					= 50;
	
	
	// A011 Protocol Command definitions.  
	
	final static byte         		COMMAND_A011_XFER_ABORT					= 0;
	final static byte         		COMMAND_A011_XFER_ALMANAC				= 4;
	final static byte         		COMMAND_A011_XFER_ROUTES				= 8;
	final static byte         		COMMAND_A011_XFER_TIME					= 20;
	final static byte         		COMMAND_A011_XFER_WAYPOINTS				= 21;
	final static byte         		COMMAND_A011_POWER_OFF					= 26;
	final static byte         		COMMAND_A011_UNAVAILABLE				= COMMAND_UNAVAILABLE;
	
	
	// Command ID Lookup Table (by App protocol)  
	
	static private byte[][]			commandIDs					 			= 
	{
		{ COMMAND_A010_XFER_ABORT,			COMMAND_A011_XFER_ABORT },
		{ COMMAND_A010_XFER_ALMANAC,		COMMAND_A011_XFER_ALMANAC },
		{ COMMAND_A010_XFER_POSITION,		COMMAND_A011_UNAVAILABLE },
		{ COMMAND_A010_XFER_PRX_WAYPOINTS,	COMMAND_A011_UNAVAILABLE },
		{ COMMAND_A010_XFER_ROUTES,			COMMAND_A011_XFER_ROUTES },
		{ COMMAND_A010_XFER_TIME,			COMMAND_A011_XFER_TIME },
		{ COMMAND_A010_XFER_TRACKS,			COMMAND_A011_UNAVAILABLE },
		{ COMMAND_A010_XFER_WAYPOINTS,		COMMAND_A011_XFER_WAYPOINTS },
		{ COMMAND_A010_POWER_OFF,			COMMAND_A011_POWER_OFF },
		{ COMMAND_A010_PVT_START,			COMMAND_A011_UNAVAILABLE },
		{ COMMAND_A010_PVT_END,				COMMAND_A011_UNAVAILABLE }
	};
	
	
	// Command ID String Lookup Table (by App protocol)  
	
	static private String[][]			commandIDStrings							= 
	{
		{ "XFER_ABORT",				"XFER_ABORT" },
		{ "XFER_ALMANAC",			"XFER_ALMANAC" },
		{ "XFER_POSITION",			"UNAVAILABLE" },
		{ "XFER_PRX_WAYPOINTS",		"UNAVAILABLE" },
		{ "XFER_ROUTES",			"XFER_ROUTES" },
		{ "XFER_TIME",				"XFER_TIME" },
		{ "XFER_TRACKS",			"UNAVAILABLE" },
		{ "XFER_WAYPOINTS",			"XFER_WAYPOINTS" },
		{ "POWER_OFF",				"POWER_OFF" },
		{ "PVT_START",				"UNAVAILABLE" },
		{ "PVT_END",				"UNAVAILABLE" }
	};
	
	
	//***************************************************************************
	//*
	//* 	GPS Model Specific App/Data Protocol tables
	//*
	//***************************************************************************/
	
	private short[][]	DEFAULT_PROTOCOL_TABLE	=		// Associates app and data protocols
	{													// zero = protocol not available
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 },
		{ 0, 0, 0, 0 }
	};


	// Associates app and data protocols for various GPS product ID's
	// zero entry = protocol not supported by specific GPS device
	
	protected short[][][]	PROTOCOL_TABLE							= null;

	
	//***************************************************************************
	//*
	//* 	Attributes
	//*
	//***************************************************************************/
	
	private	short						linkProtocol				= 0;
	
	private short[][]					protocolTable				= DEFAULT_PROTOCOL_TABLE;
	
	
	
	//***************************************************************************
	//*
	//* 	Constructors/Initializers
	//*
	//***************************************************************************/

	public Protocol()
	{
		
	}
	
	private void initializeProtocolTable()
	{
		// The following is an UGLY workaround for a Jump problem.  The code that Jump generates to initialize
		// a large static array ends up producing an assembler jump instruction that goes out of range. Creating
		// and initializing the PROTOCOL_TABLE dynamically and in segments seems to work around this issue.  It also
		// allows us to GC the array once we have finished using it.
		
		PROTOCOL_TABLE = new short[ 54 ][ 10 ][ 4 ];
		
		init1();
		init2();
		init3();
		init4();
		init5();
		init6();
	}
	
	private void init1()
	{
		short[][] PROTOCOL_TABLE_ID_7 = {													
			{ 10, 0, 0, 0 },									//  ID = 7
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 0, 0, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 7, -1, 1 }										// ID, < SW Ver: -1 = ALL, Link Protocol
		};
		
		short[][] PROTOCOL_TABLE_ID_25 = {														
			{ 10, 0, 0, 0 },									// ID = 25
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 25, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_13 = {													
			{ 10, 0, 0, 0 },									// ID = 13
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 13, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_14 = {													
			{ 10, 0, 0, 0 },									// ID = 14
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 14, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_15 = {												
			{ 10, 0, 0, 0 },									// ID = 15
			{ 100, 151, 0, 0 },
			{ 200, 200, 151, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 151, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 15, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_18 = {													
			{ 10, 0, 0, 0 },									// ID = 18
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 18, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_20 = {													
			{ 11, 0, 0, 0 },									// ID = 20
			{ 100, 150, 0, 0 },
			{ 200, 201, 150, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 450, 0, 0 },
			{ 500, 550, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 20, -1, 2 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_22 = {													
			{ 10, 0, 0, 0 },									// ID = 22
			{ 100, 152, 0, 0 },
			{ 200, 200, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 152, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 22, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_23 = {													
			{ 10, 0, 0, 0 },									// ID = 23
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 23, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_24 = {													
			{ 10, 0, 0, 0 },									// ID = 24
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 24, -1, 1 }										
		};
		
		PROTOCOL_TABLE[ 0 ] = PROTOCOL_TABLE_ID_7;													
		PROTOCOL_TABLE[ 1 ] = PROTOCOL_TABLE_ID_25;														
		PROTOCOL_TABLE[ 2 ] = PROTOCOL_TABLE_ID_13;													
		PROTOCOL_TABLE[ 3 ] = PROTOCOL_TABLE_ID_14;													
		PROTOCOL_TABLE[ 4 ] = PROTOCOL_TABLE_ID_15;													
		PROTOCOL_TABLE[ 5 ] = PROTOCOL_TABLE_ID_18;													
		PROTOCOL_TABLE[ 6 ] = PROTOCOL_TABLE_ID_20;													
		PROTOCOL_TABLE[ 7 ] = PROTOCOL_TABLE_ID_22;													
		PROTOCOL_TABLE[ 8 ] = PROTOCOL_TABLE_ID_23;													
		PROTOCOL_TABLE[ 9 ] = PROTOCOL_TABLE_ID_24;
	}

	private void init2()
	{
		short[][] PROTOCOL_TABLE_ID_29A = {										
			{ 10, 0, 0, 0 },									// ID = 29, SW < 4.0
			{ 100, 101, 0, 0 },
			{ 200, 201, 101, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 101, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 29, 400, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_29B = {													
			{ 10, 0, 0, 0 },									// ID = 29, SW >= 4.0
			{ 100, 102, 0, 0 },
			{ 200, 202, 102, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 102, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 29, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_31 = {													
			{ 10, 0, 0, 0 },									// ID = 31
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 31, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_33 = {													
			{ 11, 0, 0, 0 },									// ID = 33
			{ 100, 150, 0, 0 },
			{ 200, 201, 150, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 450, 0, 0 },
			{ 500, 550, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 33, -1, 2 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_34 = {													
			{ 11, 0, 0, 0 },									// ID = 34
			{ 100, 150, 0, 0 },
			{ 200, 201, 150, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 450, 0, 0 },
			{ 500, 550, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 34, -1, 2 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_35 = {													
			{ 10, 0, 0, 0 },									// ID = 35
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 35, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_36A = {													
			{ 10, 0, 0, 0 },									// ID = 36, SW < 3.00
			{ 100, 152, 0, 0 },
			{ 200, 200, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 152, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 36, 300, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_36B = {													
			{ 10, 0, 0, 0 },									// ID = 36, SW >= 3.00
			{ 100, 152, 0, 0 },
			{ 200, 200, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 36, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_39 = {													
			{ 10, 0, 0, 0 },									// ID = 39
			{ 100, 151, 0, 0 },
			{ 200, 201, 151, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 39, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_41 = {													
			{ 10, 0, 0, 0 },									// ID = 41
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 41, -1, 1 }										
		};
		
		PROTOCOL_TABLE[ 10 ] = PROTOCOL_TABLE_ID_29A;
		PROTOCOL_TABLE[ 11 ] = PROTOCOL_TABLE_ID_29B;
		PROTOCOL_TABLE[ 12 ] = PROTOCOL_TABLE_ID_31;
		PROTOCOL_TABLE[ 13 ] = PROTOCOL_TABLE_ID_33;
		PROTOCOL_TABLE[ 14 ] = PROTOCOL_TABLE_ID_34;
		PROTOCOL_TABLE[ 15 ] = PROTOCOL_TABLE_ID_35;
		PROTOCOL_TABLE[ 16 ] = PROTOCOL_TABLE_ID_36A;
		PROTOCOL_TABLE[ 17 ] = PROTOCOL_TABLE_ID_36B;	
		PROTOCOL_TABLE[ 18 ] = PROTOCOL_TABLE_ID_39;	
		PROTOCOL_TABLE[ 19 ] = PROTOCOL_TABLE_ID_41;	
	}

	private void init3()
	{
		
		short[][] PROTOCOL_TABLE_ID_42 = {													
			{ 10, 0, 0, 0 },									// ID = 42
			{ 100, 100, 0, 0 },
			{ 200, 200, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 42, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_44 = {												
			{ 10, 0, 0, 0 },									// ID = 44
			{ 100, 101, 0, 0 },
			{ 200, 201, 101, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 101, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 44, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_45 = {													
			{ 10, 0, 0, 0 },									// ID = 45
			{ 100, 152, 0, 0 },
			{ 200, 201, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 45, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_47 = {													
			{ 10, 0, 0, 0 },									// ID = 47
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 47, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_48 = {													
			{ 10, 0, 0, 0 },									// ID = 48
			{ 100, 154, 0, 0 },
			{ 200, 201, 154, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 48, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_49 = {												
			{ 10, 0, 0, 0 },									// ID = 49
			{ 100, 102, 0, 0 },
			{ 200, 201, 102, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 102, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 49, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_50 = {													
			{ 10, 0, 0, 0 },									// ID = 50
			{ 100, 152, 0, 0 },
			{ 200, 201, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 50, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_52 = {													
			{ 11, 0, 0, 0 },									// ID = 52
			{ 100, 150, 0, 0 },
			{ 200, 201, 150, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 450, 0, 0 },
			{ 500, 550, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 52, -1, 2 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_53 = {													
			{ 10, 0, 0, 0 },									// ID = 53
			{ 100, 152, 0, 0 },
			{ 200, 201, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 53, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_55 = {													
			{ 10, 0, 0, 0 },									// ID = 55
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 55, -1, 1 }										
		};
		
		PROTOCOL_TABLE[ 20 ] = PROTOCOL_TABLE_ID_42;
		PROTOCOL_TABLE[ 21 ] = PROTOCOL_TABLE_ID_44;
		PROTOCOL_TABLE[ 22 ] = PROTOCOL_TABLE_ID_45;
		PROTOCOL_TABLE[ 23 ] = PROTOCOL_TABLE_ID_47;	
		PROTOCOL_TABLE[ 24 ] = PROTOCOL_TABLE_ID_48;	
		PROTOCOL_TABLE[ 25 ] = PROTOCOL_TABLE_ID_49;	
		PROTOCOL_TABLE[ 26 ] = PROTOCOL_TABLE_ID_50;	
		PROTOCOL_TABLE[ 27 ] = PROTOCOL_TABLE_ID_52;
		PROTOCOL_TABLE[ 28 ] = PROTOCOL_TABLE_ID_53;
		PROTOCOL_TABLE[ 29 ] = PROTOCOL_TABLE_ID_55;
	}

	private void init4()
	{
		short[][] PROTOCOL_TABLE_ID_56 = {													
			{ 10, 0, 0, 0 },									// ID = 56
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 56, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_59 = {												
			{ 10, 0, 0, 0 },									// ID = 59
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 59, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_61 = {													
			{ 10, 0, 0, 0 },									// ID = 61
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 61, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_62 = {												
			{ 10, 0, 0, 0 },									// ID = 62
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 62, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_64 = {												
			{ 11, 0, 0, 0 },									// ID = 64
			{ 100, 150, 0, 0 },
			{ 200, 201, 150, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 450, 0, 0 },
			{ 500, 551, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 64, -1, 2 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_71 = {													
			{ 10, 0, 0, 0 },									// ID = 71
			{ 100, 155, 0, 0 },
			{ 200, 201, 155, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 71, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_72 = {													
			{ 10, 0, 0, 0 },									// ID = 72
			{ 100, 104, 0, 0 },
			{ 200, 201, 104, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 72, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_73 = {												
			{ 10, 0, 0, 0 },									// ID = 73
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 73, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_74 = {													
			{ 10, 0, 0, 0 },									// ID = 74
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 500, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 74, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_76 = {												
			{ 10, 0, 0, 0 },									// ID = 76
			{ 100, 102, 0, 0 },
			{ 200, 201, 102, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 102, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 76, -1, 1 }										
		};
		
		PROTOCOL_TABLE[ 30 ] = PROTOCOL_TABLE_ID_56;
		PROTOCOL_TABLE[ 31 ] = PROTOCOL_TABLE_ID_59;
		PROTOCOL_TABLE[ 32 ] = PROTOCOL_TABLE_ID_61;	
		PROTOCOL_TABLE[ 33 ] = PROTOCOL_TABLE_ID_62;
		PROTOCOL_TABLE[ 34 ] = PROTOCOL_TABLE_ID_64;	
		PROTOCOL_TABLE[ 35 ] = PROTOCOL_TABLE_ID_71;
		PROTOCOL_TABLE[ 36 ] = PROTOCOL_TABLE_ID_72;	
		PROTOCOL_TABLE[ 37 ] = PROTOCOL_TABLE_ID_73;	
		PROTOCOL_TABLE[ 38 ] = PROTOCOL_TABLE_ID_74;	
		PROTOCOL_TABLE[ 39 ] = PROTOCOL_TABLE_ID_76;	
	}

	private void init5()
	{
		short[][] PROTOCOL_TABLE_ID_77A = {													
			{ 10, 0, 0, 0 },									// ID = 77, SW < 3.01
			{ 100, 100, 0, 0 },
			{ 200, 201, 100, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 400, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 77, 301, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_77B = {												
			{ 10, 0, 0, 0 },									// ID = 77, SW < 3.50
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 77, 301, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_77C = {													
			{ 10, 0, 0, 0 },									// ID = 77, SW < 3.61
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 77, 361, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_77D = {													
			{ 10, 0, 0, 0 },									// ID = 77, SW >=3.61
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 77, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_87 = {													
			{ 10, 0, 0, 0 },									// ID = 87
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 87, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_88 = {												
			{ 10, 0, 0, 0 },									// ID = 88
			{ 100, 102, 0, 0 },
			{ 200, 201, 102, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 102, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 88, -1, 1 }										
		};
		
		
		short[][] PROTOCOL_TABLE_ID_95 = {													
			{ 10, 0, 0, 0 },									// ID = 95
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 95, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_96 = {												
			{ 10, 0, 0, 0 },									// ID = 96
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 96, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_97 = {												
			{ 10, 0, 0, 0 },									// ID = 97
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 97, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_98 = {												
			{ 11, 0, 0, 0 },									// ID = 98
			{ 100, 150, 0, 0 },
			{ 200, 201, 150, 0 },
			{ 0, 0, 0, 0 },
			{ 400, 450, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 98, -1, 2 }										
		};
		
		PROTOCOL_TABLE[ 40 ] = PROTOCOL_TABLE_ID_77A;	
		PROTOCOL_TABLE[ 41 ] = PROTOCOL_TABLE_ID_77B;	
		PROTOCOL_TABLE[ 42 ] = PROTOCOL_TABLE_ID_77C;	
		PROTOCOL_TABLE[ 43 ] = PROTOCOL_TABLE_ID_77D;	
		PROTOCOL_TABLE[ 44 ] = PROTOCOL_TABLE_ID_87;	
		PROTOCOL_TABLE[ 45 ] = PROTOCOL_TABLE_ID_88;
		PROTOCOL_TABLE[ 46 ] = PROTOCOL_TABLE_ID_95;
		PROTOCOL_TABLE[ 47 ] = PROTOCOL_TABLE_ID_96;
		PROTOCOL_TABLE[ 48 ] = PROTOCOL_TABLE_ID_97;	
		PROTOCOL_TABLE[ 49 ] = PROTOCOL_TABLE_ID_98;	
	}

	private void init6()
	{
		short[][] PROTOCOL_TABLE_ID_100 = {												
			{ 10, 0, 0, 0 },									// ID = 100
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 100, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_105 = {															
			{ 10, 0, 0, 0 },									// ID = 105
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 105, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_106 = {															
			{ 10, 0, 0, 0 },									// ID = 106
			{ 100, 103, 0, 0 },
			{ 200, 201, 103, 0 },
			{ 300, 300, 0, 0 },
			{ 400, 403, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 106, -1, 1 }										
		};
		
		short[][] PROTOCOL_TABLE_ID_112 = {															
			{ 10, 0, 0, 0 },									// ID = 112
			{ 100, 152, 0, 0 },
			{ 200, 201, 152, 0 },
			{ 300, 300, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 500, 501, 0, 0 },
			{ 600, 600, 0, 0 },
			{ 700, 700, 0, 0 },
			{ 0, 0, 0, 0 },
			{ 112, -1, 1 }										
		};
		
		
		PROTOCOL_TABLE[ 50 ] = PROTOCOL_TABLE_ID_100;	
		PROTOCOL_TABLE[ 51 ] = PROTOCOL_TABLE_ID_105;
		PROTOCOL_TABLE[ 52 ] = PROTOCOL_TABLE_ID_106;	
		PROTOCOL_TABLE[ 53 ] = PROTOCOL_TABLE_ID_112; 
	}
	
	
	//***************************************************************************
	//*
	//* 	Accessor Methods
	//*
	//***************************************************************************/
	
	
	/**
	 * Is the Protocol set for this GPS unit yet
	 *
	 * @return						True if defined
	 */
	
	boolean isProtocolSet()
	{
		return( linkProtocol > 0 );
	}
	
	
	/**
	 * Get  Link Protocol being used
	 *
	 * @return				Link Protocol value
	 */
	
	short getLinkProtocol()
	{
		return( linkProtocol );
	}
	
	
	/**
	 * Get specific Application Protocol for App Protocol Type
	 *
	 * @param	appProtocolType	Application Protocol Type
	 * @return					Specific Application Protocol value
	 */
	
	short getAppProtocol( int appProtocolType )
	{
		return( protocolTable[ appProtocolType ][ 0 ] );
	}
	
	
	/**
	 * Is a specific App Protocol Type supported
	 *
	 * @param	appProtocolType 	Application Protocol type
	 * @return						True if supported
	 */
	
	boolean isAppProtocolSupported( int appProtocolType )
	{
		return( getAppProtocol( appProtocolType ) != 0 );
	}
	
	
	/**
	 * Get specific Data Protocol for App Protocol Type
	*
	* @param	appProtocolType			App Protocol Type
	* @param	dataProtocolType		Data Protocol Type
	* @return							Specific Application Protocol value
	*/
	
	short getDataProtocol( int appProtocolType, int dataProtocolType )
	{
		short		dataProtocol = DATA_PROTOCOL_UNDEFINED;
		
		if( isAppProtocolSupported( appProtocolType ) ) {
			dataProtocol = protocolTable[ appProtocolType ][ dataProtocolType ];
		}
		
		return( dataProtocol );
	}
	
	
	
	/**
	 * Return specific packet id for this protocol
	 *
	 * @param		packetIDType 	packet ID type
	 * @return		Link Protocol-specific packet ID, GARMIN_PID_UNKNOWN is packet type not supported
	 */
	
	byte	getProtocolPacketID( byte packetIDType )
	{
		return( linkPacketIDs[ packetIDType ][ linkProtocol - 1 ] );
	}
	
	
	/**
	 * Get specific CommandID for for this protocol
	 *
	 * @param	commandType	Command Type
	 * @return				Specific CommandID
	 */
	
	byte getCommandID( int commandType )
	{
		return( commandIDs[ commandType ][ getAppProtocol( APP_PROTOCOL_COMMAND ) - 10 ] );
	}
	
	
	
	//***************************************************************************
	//*
	//* 	Protocol Table Processing Methods
	//*
	//***************************************************************************/
	
	/**
	 * Find & Set a protocol table for the given product ID/SW Version
	 *
	 * @param		id		GPS Product ID
	 * @param		swver	GPS Product Software Version
	 */
	
	void setProtocolTable( short id, short swver )
	{
		short[]			protocolSelector;
		
		if( PROTOCOL_TABLE == null ) {
			initializeProtocolTable();
		}
		
		for( int i = 0; i < PROTOCOL_TABLE.length; i++ ) {
			protocolSelector = PROTOCOL_TABLE[ i ][ Protocol.APP_PROTOCOL_SELECTOR ];
			if( id == protocolSelector[ Protocol.APP_PROTOCOL_ID ] ) {
				if( protocolSelector[ Protocol.APP_PROTOCOL_SWVER ] < 0 
					|| swver < protocolSelector[ Protocol.APP_PROTOCOL_SWVER ] ) {
					linkProtocol = protocolSelector[ Protocol.APP_PROTOCOL_LINK ];
					protocolTable = PROTOCOL_TABLE[ i ];
					
					//		dumpProtocolTable( "Found Protocol Array" );
					
					break;
				}
			}
		}
		
		// Drop the table so it can be garbage collected
		// Since the setProtocolTable() is only ever called once during Garmin initialization,
		// we can get rid of it after we have done the set and save a lot of memory in the object
		// heap.
		
		PROTOCOL_TABLE = null;		
	}
	
	
	/**
	 * Process a Protocol Array packet
	 *
	 * @param		packet		Protocol Array packet
	 */
	
	void processCapabilitiesPacket( ProtocolArrayGarminPacket packet )
	{
		int							i;
		int							appProtocolIndex = -1;
		int							dataProtocolIndex = 0;
		short						protocol;
		
		protocolTable = DEFAULT_PROTOCOL_TABLE;		// reset it to zeros in case we got one from the setProtocolTable()
		
		for( i = 0; i < packet.getProtocolCount(); i++ ) {
			switch( packet.getProtocolTag( i ) ) {
				case 'P':
					appProtocolIndex = -1;
					break;
					
				case 'L':
					linkProtocol = packet.getProtocol( i );
					appProtocolIndex = -1;
					break;
					
				case 'A':
					protocol = packet.getProtocol( i );
					appProtocolIndex = protocol / 100;
					dataProtocolIndex = 0;
					protocolTable[ appProtocolIndex ][ 0 ] = protocol;
					break;
					
				case 'D':
					if( appProtocolIndex >= 0 ) {
						protocol = packet.getProtocol( i );
						dataProtocolIndex++;
						protocolTable[ appProtocolIndex ][ dataProtocolIndex ] = protocol;
					}
					break;
					
				default:
					appProtocolIndex = -1;
					break;
			}
		}
		
		//		dumpProtocolTable( "Received Protocol Array" );
	}
	
	
	/*	
	 *
	 * Dump the protocol table - Debugging use only on PC using JVM
	 *
	 */
	
	private void dumpProtocolTable( String title ) 
	{
		/*		if( Compile.DEBUG ) {
		String 		line;
		
		System.out.println( "\n" + title );
		System.out.println( "Product ID: " + productData.getProductID() + ", SW Ver: " + productData.getSoftwareVersion() );
		System.out.println( "Protocol: L" + linkProtocol );
		
		for( int i = 0; i <= Protocol.APP_PROTOCOL_LAST; i++ ) {
		line = "Protocol: A" + protocolTable[ i ][ 0 ];
		for( int j = 1; j < 4; j++ ) {
		line += ", D" + protocolTable[ i ][ j ];
		}
		System.out.println( line );
		}
		
		System.out.println( "\n" );
		}
		 */	
	}
	
	
	//***************************************************************************
	//*
	//* 	ID to String Conversion Methods
	//*
	//***************************************************************************/
	
	/**
	 * Get the Packet ID as a string for the current link protocol
	 *
	 * @param		id	The packet ID
	 * @return		Packet ID (as string)
	 */
	
	public String getPacketIDString( byte id )
	{
		String		idStr	= "UNKNOWN";
		
		switch( id ) {
			case GARMIN_PID_ERROR:
				idStr = "ERROR";
				break;
				
			case GARMIN_PID_ACK:
				idStr = "ACK";
				break;
				
			case GARMIN_PID_NACK:
				idStr = "NACK";
				break;
				
			case GARMIN_PID_PROTOCOL_ARRAY:
				idStr = "PROTOCOL_ARRAY";
				break;
				
			case GARMIN_PID_PRODUCT_REQ:
				idStr = "PRODUCT_REQ";
				break;
				
			case GARMIN_PID_PRODUCT_DATA:
				idStr = "PRODUCT_DATA";
				break;
				
			default:
				if( linkProtocol > 0 ) {
					for( int i = 0; i <= GARMIN_PID_LAST; i++ ) {
						if( id == linkPacketIDs[ i ][ linkProtocol - 1 ] ) {
							idStr = linkPacketIDStrings[ i ][ linkProtocol - 1 ];
							break;
						}
					}
				}
				break;
		}
		
		return( idStr );   
	}
	
	
	/**
	 * Get the Command ID as a string for the current link protocol
	 *
	 * @param		id	The Command ID
	 * @return		Command ID (as string)
	 */
	
	public String getCommandIDString( byte id )
	{
		String		idStr	= null;
		
		int			appProtocol = getAppProtocol( APP_PROTOCOL_COMMAND );
		
		if( appProtocol > 0 ) {	
			idStr = commandIDStrings[ id ][ appProtocol - 10 ];
		}
		
		return( idStr );
	}
	
	
}
